package org.login.handler;

import akka.actor.typed.ActorRef;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.common.akka.message.ClientUpMsg;
import org.common.akka.message.ConnectClosedMsg;
import org.common.akka.message.BaseMsg;
import org.common.netty.BaseNettyHandler;
import org.common.utils.GenIdUtils;
import org.login.akka.ConnectActorManager;

import java.net.InetSocketAddress;
import java.nio.channels.ClosedChannelException;
import java.util.HashMap;

/**
 * 自定义消息处理器
 */
@Slf4j
@ChannelHandler.Sharable
public class LoginNettyHandler extends BaseNettyHandler {

    // 登录服ctx自定义属性
    private static final AttributeKey<HashMap<String, Object>> loginContextAttr = AttributeKey.valueOf("login");

    /**
     * 收到协议数据
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, byte[] msg) throws Exception {
        HashMap<String, Object> context = this.getContextAttrMap(ctx);
        long connectId = (long)context.get("connectId");
        ConnectActorManager actorManager = ConnectActorManager.getInstance();
        ActorRef<BaseMsg> connectActor = actorManager.getConnectActor(connectId);
        if (connectActor == null) {
            connectActor = actorManager.createConnectActor(connectId, ctx);
        }
        ClientUpMsg clientUpMsg = new ClientUpMsg(msg);
        connectActor.tell(clientUpMsg);
    }


    /**
     * 建立连接
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
        String ip = address.getAddress().getHostAddress();

        HashMap<String, Object> context = this.getContextAttrMap(ctx);
        if (context == null) {
            context = new HashMap<>();
            ctx.channel().attr(loginContextAttr).set(context);
        }
        long connectId = GenIdUtils.genConnectId();
        context.put("connectId", connectId);
        context.put("ip", ip);

        if (ctx.channel().isActive()) {
            log.info("创建连接—成功:ip = {}，connectId = {}", ip, connectId);
        }
    }


    /**
     * 连接断开
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        HashMap<String, Object> contextAttrMap = this.getContextAttrMap(ctx);
        long connectId = (long) contextAttrMap.get("connectId");
        ActorRef<BaseMsg> actorRef = ConnectActorManager.getInstance().getConnectActor(connectId);
        if (actorRef != null) {
            actorRef.tell(new ConnectClosedMsg());
        } else {
            log.info("onClose时 connectActor不存在，直接跳过了。 connectId={}", connectId);
        }
        log.info("连接断开, connectId={}", connectId);
    }

    /**
     * 从ctx中获取自定义属性参数
     */
    private HashMap<String, Object> getContextAttrMap(ChannelHandlerContext ctx) {
        return ctx.channel().attr(loginContextAttr).get();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (cause instanceof ClosedChannelException) {
            return;
        }
        cause.printStackTrace();
        ctx.close();
    }
}
